package com.example.compiler;

import com.google.auto.service.AutoService;

import java.io.IOException;
import java.io.Writer;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.TypeElement;
import javax.lang.model.element.VariableElement;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic;
import javax.tools.JavaFileObject;

/**
 * @author tgw
 * @date 2021/5/18
 * @describe
 *
 * 单个activity中的拼接的
 *
 * 参考：https://www.jianshu.com/p/40c62ebf53e0
 * 存在坑 多个注解的时候  应该用for循环拼接findviewbyid的操作，以绑定多个
 */

@AutoService(Processor.class)
//@SupportedAnnotationTypes("com.example.compiler.BindView")  //该注解与 下面的getSupportedAnnotationTypes（）方法一个含义
public class BindViewProcessor extends AbstractProcessor {
    private Filer mFiler;
    private Messager mMessager;
    private Elements mElementUtils;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        mFiler = processingEnvironment.getFiler();
        mMessager = processingEnvironment.getMessager();
        mElementUtils = processingEnvironment.getElementUtils();
    }

    /**指定使用的Java版本，通常这里返回SourceVersion.latestSupported()*/
    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }

    /**指定这个注解处理器是注册给哪个注解的，这里说明是注解BindView*/
    @Override
    public Set<String> getSupportedAnnotationTypes() {
        HashSet<String> supportTypes = new LinkedHashSet<>();
        supportTypes.add(BindView.class.getCanonicalName());
        return supportTypes;
    }


    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        if (set != null && set.size() > 0) {

            Set<? extends Element> bindViewElements = roundEnvironment.getElementsAnnotatedWith(BindView.class);
            String packName = null;
            String className = null;
            for (Element element : bindViewElements) {
                //1.获取包名
                PackageElement packageElement = mElementUtils.getPackageOf(element);
                packName = packageElement.getQualifiedName().toString();
                print(String.format("package = %s", packName));
                print("注解数量" + bindViewElements.size());

                //2.注解所在的类的类名
                TypeElement enclosingElement = (TypeElement) element.getEnclosingElement();
                className = enclosingElement.getSimpleName().toString();
                print(String.format("类名 enclosindClass = %s", enclosingElement));


                //因为BindView只作用于filed，所以这里可直接进行强转
                VariableElement bindViewElement = (VariableElement) element;
                //3.获取注解的成员变量名
                String fieldName = bindViewElement.getSimpleName().toString();
                print(String.format("成员变量名 enclosindClass = %s", fieldName));
                //4.获取注解元数据
                BindView bindView = element.getAnnotation(BindView.class);
                int id = bindView.value();
                print(String.format("%s = %d", fieldName, id));
            }

            try {
                String newClassName = className + "$$BindAdapterImp";
                JavaFileObject jfo = mFiler.createSourceFile(packName + "." + newClassName, new Element[]{});
                Writer writer = jfo.openWriter();
                writer.write("package " + packName + ";");
                writer.write("\n\n");
                writer.write("import com.example.bottonknife.BindAdapter;");
                writer.write("\n\n\n");
                writer.write("public class " + newClassName + " implements BindAdapter<" + className + "> {");
                writer.write("\n\n");
                writer.write("public void bind(" + className + " target) {");
                for (Element element : bindViewElements) {
                    //因为BindView只作用于filed，所以这里可直接进行强转
                    VariableElement bindViewElement = (VariableElement) element;
                    //3.获取注解的成员变量名
                    String fieldName = bindViewElement.getSimpleName().toString();

                    //4.获取注解元数据
                    BindView bindView = element.getAnnotation(BindView.class);
                    int id = bindView.value();
                    print("有多个view绑定");
                    //绑定注解
                    writer.write("\n\n");
                    writer.write("target." + fieldName + " = target.findViewById(" + id + ");");

                }
                writer.write("\n");
                writer.write("  }");
                writer.write("\n\n");
                writer.write("}");
                writer.flush();
                writer.close();
            } catch (IOException e) {
                e.printStackTrace();
            }

            return true;
        }


        return false;
    }


    /**创建文件**/
    private void createFile(String packName, String className, String fieldName, int id) {
        print("绑定的id"+id);
        try {
            String newClassName = className + "$$BindAdapterImp";
            JavaFileObject jfo = mFiler.createSourceFile(packName + "." + newClassName, new Element[]{});
            Writer writer = jfo.openWriter();
            writer.write("package " + packName + ";");
            writer.write("\n\n");
            writer.write("import com.example.bottonknife.BindAdapter;");
            writer.write("\n\n\n");
            writer.write("public class " + newClassName + " implements BindAdapter<" + className + "> {");
            writer.write("\n\n");
            writer.write("public void bind(" + className + " target) {");
            writer.write("target." + fieldName + " = target.findViewById(" + id + ");");
            writer.write("\n");
            writer.write("  }");
            writer.write("\n\n");
            writer.write("}");
            writer.flush();
            writer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**打印编译期间的日志**/
    private void print(String msg) {
        mMessager.printMessage(Diagnostic.Kind.NOTE, msg);
    }


}
